<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
<script>
    // Generator.prototype.throw()

    
    // Generator 函数返回的遍历器对象都有一个throw方法
    // 可以在函数体外抛出错误 然后在Generator函数体内捕获
    var g = function* () {
        try {
            yield;
        } catch (e) {
            console.log('内部捕获', e);
        }
    };

    var i = g();
    i.next();

    try {
        i.throw('a');
        i.throw('b');
        i.throw('c');
    } catch (e) {
        console.log('外部捕获', e);
    }
    // 内部捕获 a
    // 外部捕获 b

    // 上面代码中遍历器对象 i 连续抛出两个错误 
    // 第一个错误被Generator函数体内的catch语句捕获
    // 第二次抛出错误 由于Generator函数内部的catch语句已经执行过了 不会再捕捉到这个错误
    // 所以这个错误被抛出了Generator函数体 被函数体外catch语句捕获


    // throw方法可以接受一个参数 该参数会被catch语句接收 建议抛出Error对象的实例
    var g = function* () {
        try {
            yield;
        } catch (e) {
            console.log(e);
        }
    };

    var i = g();
    i.next();
    i.throw(new Error('出错了！'));
    // Error: 出错了！(…)


    // 注意不要混淆遍历器对象的throw方法和全局的throw命令
    // 上面代码的错误 是用遍历器对象的throw方法抛出的 而不是用throw命令抛出的 后者只能被函数体外的catch语句捕获



    var g = function* () {
        while (true) {
            try {
                yield;
            } catch (e) {
                if (e != 'a') throw e;
                console.log('内部捕获', e);
            }
        }
    };

    var i = g();
    i.next();

    try {
        throw new Error('a');
        throw new Error('b');
    } catch (e) {
        console.log('外部捕获', e);
    }
    // 外部捕获 [Error: a]



    // 上面代码之所以只捕获了 a
    // 是因为函数体外的catch语句块 捕获了抛出的a错误 以后就不会继续try代码块里剩余的语句了
    

    // 如果Generator函数内部没有部署try...catch...代码块 那么throw方法抛出的错误 将被外部try...catch...代码块捕获

    var g = function* () {
        while (true) {
            yield;
            console.log('内部捕获', e);
        }
    };

    var i = g();
    i.next();

    try {
        i.throw('a');
        i.throw('b');
    } catch (e) {
        console.log('外部捕获', e);
    }
    // 外部捕获 a

    // 上面代码中 Generator函数g内部没有部署try...catch...代码块 所以抛出的错误直接被外部catch代码块捕获
    // 如果Generator函数内部和外部 都没有部署try...catch...代码块 那么程序将报错 直接中断执行

    var gen = function* gen(){
        yield console.log('hello');
        yield console.log('world');
    }

    var g = gen();
    g.next();
    g.throw();
    // hello
    // Uncaught undefined


    // 上面代码中 g.throw抛出错误后 没有任何try...catch代码块可以捕获这个错误 
    // 导致程序报错 中断执行


    // throw方法抛出的错误要被内部捕获 前提是必须至少执行一次next方法

    function* gen() {
        try {
            yield 1;
        } catch (e) {
            console.log('内部捕获');
        }
    }

    var g = gen();
    g.throw(1);
    // Uncaught 1


    // 上面代码中 g.throw(1)执行时 next方法一次都没有执行过
    // 这时 抛出的错误不会被内部捕获 而是直接在外部抛出 导致程序出错
    // 这种行为其实很好理解 因为第一次执行next方法 等同于启动执行 Generator 函数的内部代码 
    // 否则 Generator 函数还没有开始执行 这时throw方法抛错只可能抛出在函数外部



    // throw方法被捕获以后，会附带执行下一条yield表达式。也就是说，会附带执行一次next方法。
    // 可以看到下面代码打印b 也可以看到 部署了try catch代码块 那么遍历器throw方法抛出的错误 不会影响下一次遍历
    var gen = function* gen(){
        try {
            yield console.log('a');
        } catch (e) {
            // ...
        }
        yield console.log('b');
        yield console.log('c');
    }

    var g = gen();
    g.next() // a
    g.throw() // b
    g.next() // c



    


</script>